package com.bite.common.file.service;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.bite.common.core.constants.CacheConstants;
import com.bite.common.core.constants.Constants;
import com.bite.common.core.enums.ResultCode;
import com.bite.common.core.utils.ThreadLocalUtil;
import com.bite.common.file.config.OSSProperties;
import com.bite.common.redis.service.RedisService;
import com.bite.common.security.exception.ServiceException;
import com.bite.common.file.domain.OSSResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RefreshScope
public class OSSService {
    @Autowired
    private OSSProperties prop;

    @Autowired
    private OSSClient ossClient;

    @Autowired
    private RedisService redisService;
    //传输的最大时间等
    @Value("${file.max-time}")
    private int maxTime;

    @Value("${file.test}")
    private boolean test;

    public OSSResult uploadFile(MultipartFile file)throws Exception{
        if(!test){
            //作为一个开关,假如是测试不走这个逻辑啥的，就相当于开个数量限制
            checkUploadCount();
        }
        InputStream inputStream=null;
        try {
            //用户本地有图片命名，那么OSS存在的话(重名字会覆盖)因此要重命名，所以要保存文件类型
            String fileName;
            if(file.getOriginalFilename()!=null){
                fileName=file.getOriginalFilename().toLowerCase();
            }else{
                //假如文件连命名都没有，那么我们给他初始化一个名字，我们都是按照png处理的,一般执行前端指定png或者jpg
                fileName="a.png";
            }
            String extName = fileName.substring(fileName.lastIndexOf(".") + 1);
            inputStream=file.getInputStream();
            return upload(extName,inputStream);
        }catch (Exception e){
            log.error("OSS upload file error",e);
            throw new ServiceException(ResultCode.FAILED_FILE_UPLOAD);
        }finally {
            if(inputStream!=null){
                inputStream.close();
            }
        }
    }
   //发送文件
    private OSSResult upload(String fileType, InputStream inputStream) {
        //ObjectId 可以生成一个独一无二的类似uuid
        String key= prop.getPathPrefix()+ObjectId.next()+"."+ fileType;
        ObjectMetadata objectMetadata=new ObjectMetadata();
        objectMetadata.setObjectAcl(CannedAccessControlList.PublicRead);
        PutObjectRequest request=new PutObjectRequest(prop.getBucketName(), key,inputStream,objectMetadata);
        PutObjectResult putObjectRequest;
        try{
            putObjectRequest=ossClient.putObject(request);
        }catch (Exception e){
            log.error("OSS put object error: {}", ExceptionUtil.stacktraceToOneLineString(e,500));
            throw new ServiceException(ResultCode.FAILED_FILE_UPLOAD);
        }
        return  assembleOSSResult(key,putObjectRequest);
    }


    //头像限制次数
    private void checkUploadCount(){
        Long userId= ThreadLocalUtil.get(Constants.USER_ID,Long.class);
        Long times=redisService.getCacheMapValue(CacheConstants.USER_UPLOAD_TIMES_KEY,String.valueOf(userId),Long.class);
        if(times!=null&&times>=maxTime){
            throw new ServiceException(ResultCode.FAILED_FILE_UPLOAD_TIME_LIMIT);
        }
        redisService.incrementHashValue(CacheConstants.USER_UPLOAD_TIMES_KEY,String.valueOf(userId),1);
        if(times==null||times==0){
            long seconds= ChronoUnit.SECONDS.between(LocalDateTime.now(),
                    LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withNano(0));
            redisService.expire(CacheConstants.USER_UPLOAD_TIMES_KEY,seconds, TimeUnit.SECONDS);
        }
    }


    private OSSResult assembleOSSResult(String key, PutObjectResult putObjectResult) {
        //假如没有异常的话
        OSSResult ossResult = new OSSResult();
        //看是否拿到这个id，假如拿到就成功，失败报false
        if (putObjectResult == null || StrUtil.isBlank(putObjectResult.getRequestId())) {
            ossResult.setSuccess(false);
        } else {
            ossResult.setSuccess(true);
            ossResult.setName(FileUtil.getName(key));
        }
        return ossResult;
    }




}
